package org.avenger.bucky.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.commons.io.FileUtils;
import org.avenger.bucky.constant.ConfigFile;
import org.avenger.bucky.constant.Regex;
import org.avenger.bucky.model.Option;
import org.avenger.bucky.model.TestQuestion;
import org.avenger.bucky.util.DateUtil;

/**
 * 试题处理类
 */
public class TestQuestionHandler extends AbstractHandler {

    private static Logger log = LogManager.getLogger(TestQuestionHandler.class);

    /**
     * 字符串相似度的最高匹配度
     */
    private static final float MATCH_SIMILARITY_RATIO = 1.0F;

    /**
     * 将json文件中的数据插入到mongodb中
     */
    public void insertTestQuestion() {
        log.info("将json文件中的数据插入到mongodb中");

        File file = new File(ConfigFile.INSERT_JSON);
        try {
            String content = FileUtils.readFileToString(file, "UTF-8");
            TestQuestion testQuestion = JSONObject.parseObject(content, TestQuestion.class);
            testQuestion.setCreateTime(DateUtil.dateToString(new Date()));
            mongoManager.insertTestQuestion(testQuestion);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 查找相同或相似的TestQuestion对象
     */
//    public void findSameTestQuestion() {
//        log.info("查找相同或相似的TestQuestion对象");
//
//        try {
//            // 字符串相似度
//            float stringSimilarityRatio = Float.parseFloat(PropertiesUtil.getValue(ConfigFile.BUCKY_PROPERTIES, "string.similarity.ratio"));
//
//            // 解析insert.json文件
//            File file = new File(ConfigFile.INSERT_JSON);
//            String content = FileUtils.readFileToString(file, "GBK");
//            TestQuestion compareTestQuestion = JSONObject.parseObject(content, TestQuestion.class);
//            List<Option> compareOptionList = compareTestQuestion.getOptionList();
//
//            List<TestQuestion> existTestQuestionList = null;//mongoManager.findSimilarTestQuestionByRegex(compareTestQuestion);
//            for(int i=0; i<existTestQuestionList.size(); i++){
//                TestQuestion existTestQuestion = existTestQuestionList.get(i);
//                if (null != existTestQuestion.getOptionList() && existTestQuestion.getOptionList().size() > 0){
//                    List<Option> existOptionList = existTestQuestion.getOptionList();
//                    float totalSimilarityRatio = 0.0F;
//                    for (int x=0; x<existOptionList.size(); x++){
//                        Option existOption = existOptionList.get(x);
//                        float similarityRatio = 0.0F;
//                        for (int y=x; y<compareOptionList.size(); y++){
//                            Option compareOption = compareOptionList.get(y);
//                            float tempSimilarityRatio = StringUtil.getSimilarityRatio(existOption.getContent(), compareOption.getContent());
//                            if (MATCH_SIMILARITY_RATIO == tempSimilarityRatio){
//                                similarityRatio = MATCH_SIMILARITY_RATIO;
//                                break;
//                            } else {
//                                similarityRatio += tempSimilarityRatio;
//                            }
//                        }
//                        similarityRatio = similarityRatio / compareOptionList.size();
//                        totalSimilarityRatio += similarityRatio;
//                    }
//                    totalSimilarityRatio = totalSimilarityRatio / existOptionList.size();
//
//                    if (totalSimilarityRatio > stringSimilarityRatio) {
//                        log.warn("ObjectId为【" +existTestQuestion.getId() + "】的文档与将要添加的文档高度相似");
//                    }
//                }
//
//            }
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//    }

    /**
     * 根据正则表达式，查找TestQuestion类型的对象
     */
    public void findSimilarTestQuestionByRegex(){
        log.info("根据正则表达式，查找TestQuestion类型的对象");

        File file = new File(ConfigFile.INSERT_JSON);
        try {
            // 加载insert.json文件中的数据
            String insertJsonFileContent = FileUtils.readFileToString(file, "GBK");
            TestQuestion testQuestion = JSONObject.parseObject(insertJsonFileContent, TestQuestion.class);

            // 加载忽略的选项
            List<String> ignoreOptionList = mongoManager.findContentInIgnoreOptionTable();

            // subject属性
            String subject = testQuestion.getSubject();
            // 拼凑正则表达式
            char[] subjectCharArray = subject.toCharArray();
            List<String> subjectList = new ArrayList<>();
            for (int j=0; j<subjectCharArray.length; j++){
                // 在正则中一些有意义的符号前加\
                if (Regex.KEY_MARK.contains(String.valueOf(subjectCharArray[j]))){
                    subjectList.add("\\" + subjectCharArray[j]);
                } else {
                    subjectList.add(String.valueOf(subjectCharArray[j]));
                }
            }
            final String regexSubject = String.join(".*", subjectList);
            Pattern subjectPattern = Pattern.compile("^.*" + regexSubject + ".*$", Pattern.CASE_INSENSITIVE);

            // option_list属性
            List<Option> optionList = testQuestion.getOptionList();
            List<Pattern> optionPatternList = new ArrayList<>();
            if (null != optionList && optionList.size() > 0) {
                for (int i = 0; i < optionList.size(); i++) {
                    Option option = optionList.get(i);
                    String content = option.getContent();

                    // 如果是应当忽略的选项，则continue
                    if (ignoreOptionList.contains(content)) {
                        log.info("选项【" + content + "】被忽略了");
                        continue;
                    }

                    // 拼凑正则表达式
                    char[] contentCharArray = content.toCharArray();
                    List<String> contentList = new ArrayList<>();
                    for (int j = 0; j < contentCharArray.length; j++) {
                        // 在正则中一些有意义的符号前加\
                        if (Regex.KEY_MARK.contains(String.valueOf(contentCharArray[j]))) {
                            contentList.add("\\" + contentCharArray[j]);
                        } else {
                            contentList.add(String.valueOf(contentCharArray[j]));
                        }
                    }
                    final String regexContent = String.join(".*", contentList);
                    Pattern optionPattern = Pattern.compile("^.*" + regexContent + ".*$", Pattern.CASE_INSENSITIVE);
                    optionPatternList.add(optionPattern);
                }
            }

            // 查找相似的TestQuestion
            List<TestQuestion> testQuestionList = mongoManager.findSimilarTestQuestionByRegex(subjectPattern, optionPatternList);
            // 打印
            if (null != testQuestionList && testQuestionList.size() > 0){
                for (int i=0; i<testQuestionList.size(); i++){
                    TestQuestion similarTestQuestion = testQuestionList.get(i);
                    // 格式化为json字符串
                    String similarTestQuestionJson = JSON
                        .toJSONString(similarTestQuestion, SerializerFeature.PrettyFormat,
                            SerializerFeature.WriteMapNullValue,
                            SerializerFeature.WriteDateUseDateFormat);
                    log.info("发现了相似的TestQuestion对象，它的ObjectId为【" + similarTestQuestion.getId().toString() + "】，下面是相似的属性：");
                    System.out.println(similarTestQuestionJson);
                    System.out.println("--------------------------------------------------------------------------------------");
                }
            } else {
                log.info("没有发现了相似的TestQuestion对象");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
